/*
gobanjs - html5 SGF viewer for the game of Go 

Copyright (C) 2013  Daniel Cioata
Visit http://www.govortex.ro/ for documentation, updates and examples.

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/    

"use strict";
function Goban()
{
    this.handi_19x19=[3,3,3,9,3,15,9,3,9,9,9,15,15,3,15,9,15,15];
    this.handi_13x13=[3,3,3,6,3,9,6,3,6,6,6,9,9,3,9,6,9,9];
    this.handi_9x9=[2,2,2,4,2,6,4,2,4,4,4,6,6,2,6,4,6,6];
    
    this.SAMECOLOR         =0;
    this.DIFFERENTCOLOR    =1;
    this.MARGIN            =2;
    this.EMPTY             =3;
    this.VISITED           =4;
    
    this.stones=null;
    this.boardsize=19;
        
    this.stoneIndex=0;
    this.bounds={left:0,top:0,right:19,bottom:19};
}

Goban.prototype.checkBounds=function(x,y)
{
    if((x<0)||(x>=this.boardsize)||(y<0)||(y>=this.boardsize))
        return false;
    return true;
}

Goban.prototype.setBounds=function(bounds,gap)
{ 
    this.m_bounds=bounds;
    this.m_bounds.left-=gap;
    this.m_bounds.top-=gap;
    this.m_bounds.bottom+=gap;
    this.m_bounds.right+=gap;

    if(this.m_bounds.left<0)
        this.m_bounds.left=0;    
        
    if(this.m_bounds.top<0)
        this.m_bounds.top=0;     
          
    if(this.m_bounds.right>this.boardSize)
        this.m_bounds.right=this.boardSize;
        
    if(this.m_bounds.bottom>this.boardSize)
        this.m_bounds.bottom=this.boardSize;    
}

Goban.prototype.init=function(size)
{
    var i,j;
    this.boardsize=size;
    this.stones=new Array();
    for(i=0;i<this.boardsize;i++)
    {
        this.stones[i]=new Array(this.boardsize);
        for(j=0;j<this.boardsize;j++)
            this.stones[i][j]=null;
    }
}

Goban.prototype.addMove=function(stone)
{	        
    if((stone.x >=0) && (stone.y >=0))
    {
	    this.stones[stone.x][stone.y]=stone;  	    	    	
	}
};

Goban.prototype.remMove=function(stone)
{    
    if((stone.x >=0) && (stone.y >=0))
    {        
   		this.stones[stone.x][stone.y]=null;
    }
}


Goban.prototype.checkNeighbor=function(stone,x,y)
{    
    
    if((x<0)||(x>=this.boardsize)||(y<0)||(y>=this.boardsize))
        return this.MARGIN;       
    
	if(this.stones[x][y]==null)
	    return this.EMPTY;	    
	    
    if(this.stones[x][y].visited)
       return this.VISITED;	       
       
    if((this.stones[x][y].color==stone.color))
    {                          
        return this.SAMECOLOR;
    }
    else
        return this.DIFFERENTCOLOR;
}

Goban.prototype.createGroup=function(stone)
{
    var st,group,rv,ind,xx,yy,k,haslib;
    
    st=stone;
    group=new Array();
    group.push(st);
    stone.visited=true;
    ind=0;
    haslib=false;
    
    while(ind<group.length)
    {   
        for(k=0;k<4;k++)
        {
            xx=st.x;
            yy=st.y;
            if(k==0) xx--;
            if(k==1) yy--;
            if(k==2) xx++;
            if(k==3) yy++;            
            
            rv=this.checkNeighbor(st,xx,yy);
            
            if((rv==this.SAMECOLOR) && this.stones[xx][yy].visited==false)
            {
                group.push(this.stones[xx][yy]);
                this.stones[xx][yy].visited=true;
            }
            else if(rv==this.EMPTY)
            {            
                haslib=true;
                break;
            }
        }
        ind++;
        st=group[ind];
    }
    
    if(haslib)
    {
        for(k=0;k<group.length;k++)
        {
            group[k].visited=false;
        }
        group=null;
    }
    return group;
}

Goban.prototype.makeMove=function(node)
{
    var group,i,j,k,rv,grp,st,xx,yy,stone;	
    
    stone=node.stone;
    
    if(stone==null)
    {
        console.log("stone==null");
        return;
    }

    this.stoneIndex++;
    stone.index=this.stoneIndex;

    this.addMove(stone);	
    if(node.captured !=null)
    {
        for(k=0;k<node.captured.length;k++)    
            this.remMove(node.captured[k]);
    }    
    else
    {
        for(k=0;k<4;k++)
        {
            xx=stone.x;
            yy=stone.y;
            if(k==0) xx--;
            if(k==1) yy--;
            if(k==2) xx++;
            if(k==3) yy++;            
            if(this.checkNeighbor(stone,xx,yy)==this.DIFFERENTCOLOR)
            {
                group=this.createGroup(this.stones[xx][yy]);
                if(group!=null)
                {
                    if(node.captured==null)
                        node.captured=group;
                    else
                        node.captured=node.captured.concat(group);
                }
            }
         }
         if(node.captured!=null)
         { 
             for(k=0;k<node.captured.length;k++)
             {
                 node.captured[k].visited=false;
                 this.remMove(node.captured[k]);
             }
         }  	    
    }	
}

Goban.prototype.takeMove=function(node)
{
    var i;    
            

    if((node!=null) && (node.captured!=null))
    {
        for(i=0;i<node.captured.length;i++)
        {
            this.addMove(node.captured[i]);
        }
    }
    if(node.stone!=null)
        this.remMove(node.stone);
    else
        return false;    
    this.stoneIndex--;
    return true;
}

Goban.prototype.clear=function ()
{
    var i,j;
    for(i=0;i<this.boardSize;i++)
    	for(j=0;j<this.boardSize;j++)
    	{
    		if(this.m_stones[i][j]!=null)
    		{
               this.remMove(this.m_stones[i][j]);
    		}
    	}
	this.stoneIndex=0;
}


